﻿using System;
using System.Collections.ObjectModel;
using System.ServiceModel.DomainServices.Client;
using System.Windows.Input;
using OpenLightGroup.Common.MVVM;
using OpenLightGroup.Common.UserManagement.Web;
using System.ComponentModel.DataAnnotations;
using System.ServiceModel.DomainServices.Client.ApplicationServices;

namespace OpenLightGroup.Common.UserManagement
{
    public class UserManagementViewModel : BaseViewModel
    {

        private Web.UserManagementContext _context
             = new Web.UserManagementContext();

        private Web.User _currentUser;
        private string _searchType;
        private string _searchTerm;
        private string _newPassword;
        private UserRegistration _newUser;

        public UserManagementViewModel()
        {

            this.CreateUserCommand = new DelegateCommand(CreateUser);
            this.GetRolesCommand = new DelegateCommand(GetRoles);

            this.AddRoleCommand = new DelegateCommand(AddRole);
            this.DeleteRoleCommand = new DelegateCommand(DeleteRole);

            this.FindUserCommand = new DelegateCommand(FindUser);
            this.ChangePasswordCommand = new DelegateCommand(ChangePassword, CanChangePassword);

            this.SaveChangesCommand = new DelegateCommand(SaveChanges);


            this.CurrentUser = new User();
            this.NewRole = new Role();
            this.NewUser = new UserRegistration();

            this.Roles = new ObservableCollection<Web.Role>();
            this.Users = new ObservableCollection<Web.User>();

            this._context.PasswordRetrievalEnabled(GetPasswordRetrievalEnabledCompleted, null);

           
         
        }

        #region Properties

        public Web.Role NewRole { get; set; }

        private bool _passwordRetrievalEnabled;

        public bool PasswordRetrievalEnabled
        {
            get { return _passwordRetrievalEnabled; }
            set            
            {
                if (_passwordRetrievalEnabled != value)
                {
                      _passwordRetrievalEnabled = value;
                      this.RaisePropertyChanged("CanChangePassword");
                }
              
            }
        }


        public Web.User CurrentUser
        {
            get { return _currentUser; }
            set
            {
                if (_currentUser != value)
                {
                    _currentUser = value;
                    this.RaisePropertyChanged("CurrentUser");
                }
            }
        }


        public UserRegistration NewUser
        {
            get { return _newUser; }
            set { _newUser = value; }
        }

        public ObservableCollection<Web.Role> Roles { get; set; }

        public ObservableCollection<Web.User> Users { get; set; }

        public string SearchType
        {
            get { return _searchType; }
            set
            {
                if (_searchType != value)
                {
                    _searchType = value;
                    this.RaisePropertyChanged("SearchType");
                }

            }
        }

        public string SearchTerm
        {
            get { return _searchTerm; }
            set
            {
                if (_searchTerm != value)
                {
                    _searchTerm = value;
                    this.RaisePropertyChanged("SearchTerm");
                }
            }
        }

        public string NewPassword
        {
            get { return _newPassword; }
            set
            {
                if (_newPassword != value)
                {
                    _newPassword = value;
                    this.RaisePropertyChanged("NewPassword");
                }

            }
        }

        #endregion


        #region Commands

        #region Role Commands

        public ICommand AddRoleCommand { get; private set; }
        private void AddRole(object arg)
        {

            if (Validator.TryValidateObject(this.NewRole, new ValidationContext(this.NewRole, null, null), this.NewRole.ValidationErrors))
            {
                this.Roles.Add(this.NewRole);

                _context.Roles.Add(this.NewRole);

                this.SaveChanges(arg);

                this.NewRole = new Role();

            }

        }

        public ICommand DeleteRoleCommand { get; private set; }
        private void DeleteRole(object arg)
        {

            Role role = arg as Role;

            this.Roles.Remove(role);

            _context.Roles.Remove(role);

            this.SaveChanges(arg);

        }

        public ICommand GetRolesCommand { get; private set; }
        private void GetRoles(object arg)
        {

            _context.Load(_context.GetRolesQuery(), LoadRoles, null);

            this.UpdateIsBusy();
        }


        #endregion

        #region User Commands

        public ICommand CreateUserCommand { get; private set; }
        private void CreateUser(object arg)
        {
            Validator.TryValidateObject(this.NewUser, new ValidationContext(this.NewUser, null, null), this.NewUser.ValidationErrors);

            if (!this.NewUser.HasValidationErrors)
            {
                _context.CreateUser(this.NewUser, CreateUserCompleted, null);

                this.Users.Add(new User() { Email = this.NewUser.Email, Roles = this.NewUser.Roles, UserName = this.NewUser.UserName });

                this.UpdateIsBusy();
            }
        }

        public ICommand FindUserCommand { get; private set; }
        private void FindUser(object arg)
        {

            _context.Load<Web.User>(_context.FindUsersQuery(this.SearchType, this.SearchTerm), LoadUsers, null);

            this.UpdateIsBusy();

        }

        public ICommand ChangePasswordCommand { get; private set; }
        private void ChangePassword(object arg)
        {

            this._context.ChangePassword(this.CurrentUser.UserName, arg.ToString(), ChangePasswordCompleted, null);

            this.UpdateIsBusy();

        }
        private bool CanChangePassword(object arg)
        {
            return this.PasswordRetrievalEnabled;
        }

        #endregion


        public ICommand SaveChangesCommand { get; private set; }
        private void SaveChanges(object arg)
        {


            _context.SubmitChanges(SubmitChangesCompleted, null);

            this.UpdateIsBusy();

        }

        #endregion

        #region Event Handlers

        private void ChangePasswordCompleted(InvokeOperation obj)
        {
            if (obj.HasError)
            {
                this.HandleError(obj);
            }
            else
            {
                this.NewPassword = string.Empty;
            }
        }

        private void CreateUserCompleted(InvokeOperation<CreateUserStatus> obj)
        {

            if (obj.HasError)
            {
                this.HandleError(obj);
            }
            else
            {
                switch (obj.Value)
                {
                    case CreateUserStatus.Success:
                        this.NewUser = new UserRegistration();
                        break;

                    case CreateUserStatus.InvalidUserName:
                        break;
                    case CreateUserStatus.InvalidPassword:
                        break;
                    case CreateUserStatus.InvalidQuestion:
                        break;
                    case CreateUserStatus.InvalidAnswer:
                        break;
                    case CreateUserStatus.InvalidEmail:
                        break;
                    case CreateUserStatus.DuplicateUserName:
                        break;
                    case CreateUserStatus.DuplicateEmail:
                        break;
                    case CreateUserStatus.Failure:
                        break;
                    default:
                        break;
                }

            }
        }

        private void GetPasswordRetrievalEnabledCompleted(InvokeOperation<bool> obj)
        {
            if (obj.HasError)
            {
                this.HandleError(obj);
            }
            else
            {
                this.PasswordRetrievalEnabled = obj.Value;
            }

        }

        private void LoadRoles(LoadOperation<Role> obj)
        {


            if (obj.HasError)
            {
                this.HandleError(obj);
            }
            else
            {
                this.Roles.Clear();

                foreach (var item in obj.Entities)
                {
                    this.Roles.Add(item);
                }

                this.RaisePropertyChanged("Roles");
            }

            this.UpdateIsBusy();
        }

        private void LoadUsers(LoadOperation<User> obj)
        {

            if (obj.HasError)
            {
                this.HandleError(obj);
            }
            else
            {
                this.Users.Clear();

                foreach (var item in obj.Entities)
                {
                    this.Users.Add(item);
                }

            }

            this.UpdateIsBusy();

        }

        private void SubmitChangesCompleted(SubmitOperation obj)
        {

            if (obj.HasError)
            {
                this.HandleError(obj);
            }
            else
            {

            }

            this.UpdateIsBusy();
        }


        #endregion

        #region Helper Methods

        private void HandleError(OperationBase obj)
        {
            this.Error = obj.Error;

            obj.MarkErrorAsHandled();

            this.RaisePropertyChanged("HasError");
        }
        public override void UpdateIsBusy()
        {
            this.IsBusy = _context.IsLoading || _context.IsSubmitting;
        }

        #endregion
    }
}
